/* Copyright (c) 2016 Jesper Öqvist <jesper@llbit.se> * * This file is part of Chunky. * * Chunky is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Chunky is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Chunky. If not, see <http://www.gnu.org/licenses/>. */ package se.llbit.chunky.launcher.ui; import javafx.application.Application; import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; import se.llbit.chunky.launcher.LauncherSettings; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** * JavaFX window for the Chunky launcher. */ public class ChunkyLauncherFx extends Application { private static LauncherSettings settings; private static AtomicBoolean first = new AtomicBoolean(true); private static CountDownLatch latch = new CountDownLatch(1); private static Consumer<Stage> callback; private static Stage stage; @Override public void start(Stage stage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("ChunkyLauncher.fxml")); ChunkyLauncherController controller = new ChunkyLauncherController(settings); loader.setController(controller); Parent root = loader.load(); stage.getIcons().add(new Image(getClass().getResourceAsStream("chunky-cfg.png"))); stage.setTitle("Chunky Launcher"); stage.setScene(new Scene(root)); stage.setOnShowing(controller::onShowing); ChunkyLauncherFx.stage = stage; latch.countDown(); callback.accept(stage); } /** * Starts the JavaFX application thread and calls the callback with the stage for * the Chunky Launcher. * * <p>This design is needlessly convoluted to work around the fact that JavaFX only * allows a single active Application, and no GUI elements can be created without * first launching that application. We have to use this callback method since we * want to be able to show both the first-time-setup window and the debug console * (when --console was specified) without showing the Chunky Launcher window. * When the callback is called we can be sure that the callback is called on the * application thread and that the application has been started, which makes it * possible to open other windows. If the main Chunky Launcher window should be * displayed then the callback argument can be used by calling stage.show(). */ public static void withLauncher(LauncherSettings settings, Consumer<Stage> callback) { if (first.compareAndSet(true, false)) { new Thread(() -> { ChunkyLauncherFx.settings = settings; ChunkyLauncherFx.callback = callback; launch(); }).start(); } else { try { latch.await(); Platform.runLater(() -> callback.accept(stage)); } catch (InterruptedException ignored) { // Ignored. } } } }